/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package net.cjb.malacma.rssfeed.util;

import com.sun.syndication.feed.synd.SyndCategoryImpl;
import java.util.logging.Level;
import java.util.logging.Logger;
import net.cjb.malacma.rssfeed.entity.Spam;
import static net.cjb.malacma.rssfeed.persistence.JPAController.*;

import com.sun.syndication.feed.synd.SyndEntryImpl;
import com.sun.syndication.feed.synd.SyndFeed;
import com.sun.syndication.io.FeedException;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Scanner;
import javax.servlet.http.*;
import net.cjb.malacma.rssfeed.crawler.FeedCrawler;
import net.cjb.malacma.rssfeed.entity.FeedUrl;
import net.cjb.malacma.rssfeed.entity.Tag;
import net.cjb.malacma.rssfeed.entity.UserContext;
import net.cjb.malacma.rssfeed.geolocation.GeoLocationProxy;
import net.cjb.malacma.rssfeed.geolocation.GeoLocationTO;
import net.cjb.malacma.rssfeed.googleapi.BloggerClient;
import net.cjb.malacma.rssfeed.persistence.JPAController;
import net.cjb.malacma.rssfeed.persistence.exceptions.IllegalOrphanException;
import net.cjb.malacma.rssfeed.persistence.exceptions.NonexistentEntityException;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import websphinx.Link;

/**
 *
 * @author malacma
 */
public final class FeedFacade {

    public static final String GEOIP = "GEOIP";
    public static final String MARQUEE = "marquee";
    public static final String NA = "N/A";
    public static final String QUERY = "query";
    public static final String RSS = "rss";
    public static final String SEARCHJSP = "search.jsp";
    public static final String SESSION_CURRENT_FEED = "TOKEN_SESSION";
    public static final String TAGCLOUD = "tagCloud";
    public static final String TAGS = "tags";
    public static final String TOTALRESULTS = "totalresults";
    public static final String WORDS = "words";
    public static final String COLUNA1 = "coluna1";
    public static final String COLUNA2 = "coluna2";
    public static final String HTTPDEFAULTRSS = "http://edition.cnn.com/services/rss/";
    public static final String INDEXJSP = "index.jsp";
    public static final String PINOCONTROLLERDO = "PinoController.do";
    public static final String TAG = "tag";
    public static final String RESULTS = "results";
    public static final String TWITTERBASE = "http://search.twitter.com/search.atom?";
    public static final String TWITTERWTAGS = "http://search.twitter.com/trends/weekly.json?date=";
    public static final String TRENDS = "trends";
    public static final String PROFILE = "profileDoUser";
    public static final String BINGSEARCH = "http://www.bing.com/search?go=&form=QBLH&filt=all&format=rss&q=";

    /**
     *Method to search Twitter and get trends of the week to populate Meta Tags
     *
     *
     */
    public static void searchTwitterTags(PrintWriter p, HttpServletRequest request, HttpServletResponse response) throws IOException {
        Runnable r = new Runnable() {

            public void run() {
                getTwitterTags();
            }
        };

        Thread t1 = new Thread(r);
        t1.start();

        response.sendRedirect(INDEXJSP);
    }

    /**
    @ PinoController.do?query=123&method=searchTwitter&totalresults=123
     */
    public static void searchTwitter(PrintWriter p, HttpServletRequest request, HttpServletResponse response) throws IOException, IllegalOrphanException, Exception {
        String l = request.getLocale().getLanguage();//recupera o locale da requisição
        StringBuilder sb = new StringBuilder(TWITTERBASE);
        sb.append("lang=");
        sb.append(l);
        sb.append("&q=");
        sb.append(request.getParameter(QUERY));
        sb.append("&rpp=");
        sb.append(request.getParameter(TOTALRESULTS));

        //Monta o parâmetro do Twitter para chamar o processamento do Feed
        request.setAttribute(RSS, sb.toString());

        //Processa o feed
        processFeedInfo(p, request, response);

        l = null;
        sb = null;

    }

    public static void searchMicrosoftBing(PrintWriter p, HttpServletRequest request, HttpServletResponse response) throws IOException, IllegalOrphanException, Exception {
        StringBuilder sb = new StringBuilder(BINGSEARCH);
        sb.append(request.getParameter(QUERY).toString().replace(" ","+"));

        //Monta o parâmetro do Twitter para chamar o processamento do Feed
        request.setAttribute(RSS, sb.toString());

        //Processa o feed
        processFeedInfo(p, request, response);

//        l = null;
        sb = null;

    }

    /**
     *
     * @ Salva o Feed na base para futuras consultas;
     * em uma nova thread
     */
    @SuppressWarnings("static-access")
    private static FeedUrl persistFeedTagsOrMerge(String url, String tit, SyndFeed sf) throws NonexistentEntityException, Exception {
        FeedUrl fu = findFeedByTitle(tit);
        boolean isNew = false;
        if (fu.getId() == null) {//Persist
            fu = new FeedUrl();
            fu.setTitulo(tit);
            fu.setUrl(url);
            isNew = true;
        }
        ArrayList<Tag> tags = new ArrayList<Tag>();
        List categories = sf.getCategories();
        boolean hasNewTag = false;
        for (Object o : categories) {
            String token = ((SyndCategoryImpl) o).getName();
            Tag t = findTagByTitle(token.toUpperCase());
            if (t != null) {
                continue;
            } else {
                t = new Tag();
                t.setTxt(token);
                tags.add(t);
                hasNewTag = true;
            }
        }
        if (hasNewTag || isNew) {
            mergeFeedTags(fu, tags);
        }

        tags = null;
        categories.clear();
        categories = null;

        return fu;
    }

    public static synchronized final void persistFeedUrl(final String url, final String tit, final SyndFeed sf) throws Exception {

        if (!FeedCatalog.hasElement(tit)) {
            Runnable r1 = new Runnable() {

                SyndFeed sfCopy = sf;
                FeedUrl fu;

                public void run() {
                    try {
                        fu = persistFeedTagsOrMerge(url, tit, sf);
                    } catch (NonexistentEntityException ex) {
                        Logger.getLogger(FeedFacade.class.getName()).log(Level.SEVERE, null, ex);
                    } catch (Exception ex) {
                        Logger.getLogger(FeedFacade.class.getName()).log(Level.SEVERE, null, ex);
                    } finally {
                        sfCopy = null;
                        fu = null;
                        //this.notifyAll();
                    }
                }
            };
            Thread t1 = new Thread(r1);
            t1.start();
            //t1.join();
        }

    }

    public static final SyndFeed getLastSyndFeed() throws Exception {
        FeedUrl fu = getLastFeedUrl();
        SyndFeed sf = null;
        try {
            sf = FeedFactory.getInstance(fu.getUrl());
        } catch (Exception ex) {
            ex.printStackTrace();
        } finally {
            fu = null;
            return sf;

        }

    }

    public static void persistTagsF(PrintWriter out, HttpServletRequest request, HttpServletResponse response) {
        try {
            HttpSession session = request.getSession(true);
            FeedUrl feed = (FeedUrl) session.getAttribute(SESSION_CURRENT_FEED);
            persistTags(feed, request.getParameter(TAGS));
            //@TODO Refactor this nefertiteControllerCall
            out.print("<script>");
            // out.print("alert('SUCESSO!');");
            out.print("parent.nefertiteController.closeWindow();");
            out.print("</script>");
        } catch (Exception e) {
            out.print("<script>");
            out.print("alert('ERROR!');");
            out.print("parent.nefertiteController.closeWindow();");
            out.print("</script>");
        }

    }

    public static final StringBuilder makeMapLayout(String url) {

        GeoLocationTO geoLocationTO = null;

        try {
            geoLocationTO = GeoLocationProxy.getInstance(url);
        } catch (Exception e) {
            geoLocationTO = new GeoLocationTO(e.toString(), url, url, url, url, url, url, url);
        }

        StringBuilder sb = new StringBuilder("<table title='FEED IP" + geoLocationTO.getIp() + "' width='100%' border='0'>");
        sb.append("<tr>");
        sb.append("<td>");
        sb.append("<input type='button' name='GoogleMAP' value='View GMap' onclick=\"nefertiteController.loadMap('" + geoLocationTO.getLatitude() + "','" + geoLocationTO.getLongitude() + "')\" >");
        sb.append("</td>");
        sb.append("<td nowrap='nowrap'><div align='left'><b>City</b></div></td>");
        sb.append("<td>" + geoLocationTO.getCity() + "</td>");
        sb.append("<td><div align='left'><b>Area code</b></div></td>");
        sb.append("<td>" + geoLocationTO.getAreaCode() + "</td>");
        sb.append("<td nowrap='nowrap'><div align='left'><b>Currency</b></div></td>");
        sb.append("<td>" + geoLocationTO.getCurrency() + ";</td>");
        sb.append("<td nowrap='nowrap'><div align='left'><b>Country</b></div></td>");
        sb.append("<td>" + geoLocationTO.getCountryName() + "</td>");
        sb.append("<td nowrap='nowrap'><div align='left'><b>Longitude</b></div></td>");
        sb.append("<td>" + geoLocationTO.getLongitude() + "</td>");
        sb.append("<td nowrap='nowrap'><div align='left'><b>Latitude</b></div></td>");
        sb.append("<td>" + geoLocationTO.getLatitude() + "</td>");
        sb.append("</table>");
        sb.append("<iframe id=\"cframeMap\" width=\"100%\" height=\"100%\" frameborder=\"0\"></iframe>");

        return sb;
    }

    public static void processFeedInfo(PrintWriter out, HttpServletRequest request, HttpServletResponse response) throws IOException, IllegalOrphanException, Exception {

        StringBuilder sb1 = new StringBuilder();
        StringBuilder sb2 = new StringBuilder();
        StringBuilder sb3 = new StringBuilder();
        StringBuilder sb4 = new StringBuilder();
        HttpSession session = request.getSession(true);
        String pUrlFeed = null;
        SyndFeed sf = null;
        FeedUrl fdurl = null;
        try {
            pUrlFeed = (request.getAttribute(RSS) != null ? request.getAttribute(RSS).toString() : request.getParameter(RSS));
            //Instância o FEED
            sf = (pUrlFeed != null ? FeedFactory.getInstance(pUrlFeed) : FeedFacade.getLastSyndFeed());
            fdurl = (pUrlFeed != null ? persistFeedTagsOrMerge(pUrlFeed, sf.getTitle(), sf) : persistFeedTagsOrMerge(sf.getUri(), sf.getTitle(), sf));

            //Coloca na session o objeto corrente para poder efetuar as operações de tags, comments, etc...

            session.setAttribute(SESSION_CURRENT_FEED, fdurl);

            //Inicialza a geo localização
            sb4 = makeMapLayout(fdurl.getUrl());

            sb2.append("<h2>");
            sb2.append(sf.getTitle());
            sb2.append("<br>");
            if (sf.getImage() != null && sf.getImage().getUrl() != null) {
                sb2.append("<br><img src='");
                sb2.append(sf.getImage().getUrl());
                sb2.append("'><br>");
            }
            sb2.append("<br>");
            sb2.append(sf.getLink());
            sb2.append("<br>");
            if (sf.getDescription() != null) {
                sb2.append(sf.getDescription());
                sb2.append("<br>");
            }
            if (sf.getCopyright() != null) {
                sb2.append(sf.getCopyright());
            }
            sb2.append("</h2>");

            sb1.append("<ul>");
            for (Object entry : sf.getEntries()) {
                SyndEntryImpl syndEntryImpl = (SyndEntryImpl) entry;

                String email = (syndEntryImpl.getAuthor() == null ? NA : syndEntryImpl.getAuthor());

//                //If email is not equals N/A persist it at spam class
//                if (!email.equals(NA) && !email.isEmpty()) {
//                    createSpan(email);
//                }

                sb1.append("<li><b><a href='");
                sb1.append(syndEntryImpl.getLink());
                sb1.append("' title='");
                sb1.append(syndEntryImpl.getLink());
                sb1.append(" Date:");
                sb1.append((syndEntryImpl.getUpdatedDate() == null ? NA : syndEntryImpl.getUpdatedDate()));
                sb1.append(" Author:");
                sb1.append(email);
                sb1.append("' target=_blank>");
                sb1.append(syndEntryImpl.getTitle());
                sb1.append("</a></b><br>");
                if (syndEntryImpl.getDescription() != null) {
                    sb1.append(syndEntryImpl.getDescription().getValue());
                }
                sb1.append("</li>");

                syndEntryImpl = null;
                email = null;
            }

            sb1.append("</ul>");
            sb3.append("<table width=100%><tr><td>");
            for (Tag t1 : fdurl.getTags()) {
                sb3.append("&nbsp;\n" + t1.getTxt());
            }
            sb3.append("</td></tr></table>");

        } catch (Exception ex) {
            sb1.append(ex.toString());
            sb2.append(ex.toString());
        } finally {
            session.setAttribute(COLUNA1, sb2);
            session.setAttribute(COLUNA2, sb1);
            session.setAttribute(TAGCLOUD, tagCloudData());
            session.setAttribute(MARQUEE, getBloList() + getTags());
            session.setAttribute(TAG, sb3.toString());
            session.setAttribute(GEOIP, sb4.toString());
            session.setAttribute(PROFILE, getUserLayout(request, fdurl));
            response.sendRedirect(INDEXJSP);

            pUrlFeed = null;
            fdurl = null;
            sf = null;
            sb1 = null;
            sb2 = null;
            sb3 = null;
            sb4 = null;
            session = null;

            out.close();
            out = null;
        }

    }

    public static String getUserLayout(HttpServletRequest r, FeedUrl f) {
        UserContext u = ContextFacade.getCurrentUse(r);
        if (u.getEmail() != null) {
            try {
                u.getMyFeeds().add(f);
                merge(u);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        return (u.getEmail() == null ? "NONE" : u.getEmail());
    }

    public static void updateFeed(FeedUrl f1) throws IllegalOrphanException, Exception {
        f1.setOnline();
        merge(f1);
    }

    public static void updateTag(Tag t) {
        throw new UnsupportedOperationException("Not yet implemented");
    }

    private static final String getBloList() {
        try {
            return BloggerClient.getBlogListHtmlMarquee("pino.rss.feed", "D4onde12345").toString();
        } catch (Exception ex) {
            return "<marquee>Error" + ex + "</marquee>";
        }

    }

    public static final StringBuilder makeLayout(FeedUrl f1, StringBuilder sb2) throws MalformedURLException, IllegalArgumentException, FeedException, IOException {
        SyndFeed sf;
        try {
            sf = FeedFactory.getInstance(f1.getUrl());

            sb2.append(sf.getTitle());

            if (sf.getImage() != null) {
                sb2.append("<br><img src='");
                sb2.append(sf.getImage().getUrl());
                sb2.append("'><br>");
            }

            sb2.append(sf.getLink());
            sb2.append("<br>");
            sb2.append(sf.getDescription());
            sb2.append("<br>");
            sb2.append(sf.getCopyright());
            sb2.append("</h2>");

            sb2.append("<ul>");
            for (Object entry : sf.getEntries()) {
                SyndEntryImpl syndEntryImpl = (SyndEntryImpl) entry;
                sb2.append("<li><b><a href='");
                sb2.append(syndEntryImpl.getLink());
                sb2.append("' title='");
                sb2.append(syndEntryImpl.getTitleEx().getValue());
                sb2.append("' target=_blank>");
                sb2.append(syndEntryImpl.getTitle());
                sb2.append("</a></b></li>");
                syndEntryImpl = null;
            }

        } catch (IllegalArgumentException illegalArgumentException) {
            return null;
        } catch (FeedException feedException) {
            return null;
        } catch (IOException iOException) {
            return null;
        } finally {
            f1 = null;
            sf = null;
            return sb2;
        }

    }

    /**

    {
    items : [
    { label : 'jMaki', weight : 70},
    { label : 'Web2.0', weight : 150},
    { label : 'JSON', weight : 80},
    { label : 'JavaScript', weight : 145},
    { label : 'Java', weight : 100},
    { label : 'RSS', weight : 85},
    { label : 'Autocomplete', weight : 75},
    { label : 'Sun', weight : 65, href : 'http://www.sun.com'},
    { label : 'jMaki', weight : 150},
    { label : 'Web3.0', weight : 70},
    { label : 'Phobos', weight : 105},
    { label : 'Glassfish', weight : 120},
    { label : 'RSS2.0', weight : 75},
    { label : 'Web1.0', weight : 50},
    { label : 'JavaEE', weight : 75},
    { label : 'Jersey', weight : 115},
    { label : 'Roller', weight : 150},
    { label : 'CSS', weight : 105},
    { label : 'DHTML', weight : 65},
    { label : 'Netbeans', weight : 115, href : 'http://www.netbeans.com'}
    ]
    }"
     */
    private static StringBuilder tagCloudData() {
        //JPAController jpa = new JPAController();
        StringBuilder sb = new StringBuilder();
        sb.append("{items : [");//Inicio

        HashMap<String,String> mapac = new HashMap<String,String>();

        ArrayList<FeedUrl> it = (ArrayList<FeedUrl>) findCloudEntities(80);

        int total = 0;
        for (FeedUrl f : it) {

            String[] a1 = f.getTitulo().split(" ");

            String tag = a1[a1.length - 1];
            if (!mapac.containsKey(tag)) {
                mapac.put(tag,tag);
            } else {
                continue;
            }

            int size = ((int) (f.getId().intValue() * Math.random()) + it.size());
            size = (size > 70 ? 70 : size);
            sb.append("{ label : '" + tag.replace("'", "") + "', weight : '" + size + "', href:'PinoController.do?method=processFeedInfo&rss=" + f.getUrl() + "'}");

            if (total++ < it.size()) {
                sb.append(",\n");
            }
            a1 = null;
            tag = null;
            f = null;
        }
        //Free memory
        it.clear();
        it = null;
        mapac.clear();
        mapac = null;

        sb.append("]}");//Fim
        return sb;

    }

    public static List<FeedUrl> findAllFeeds() throws Exception {
        return findAllFeedUrl();
    }

    public static List<FeedUrl> findAllOnffLine() throws Exception {
        return findOffLineFeeds();
    }

    public static void persistSpam(Spam sp) throws Exception {
        persist(sp);
    }

    public static void searchWeb(PrintWriter out, HttpServletRequest request, HttpServletResponse response) throws MalformedURLException, IOException {
        String url = (request.getParameter("url") == null ? HTTPDEFAULTRSS : request.getParameter("url"));
        FeedCrawler crawler = new FeedCrawler();
        Thread t;
        try {
            // Create a "Link" object and set it as the crawler's root
            Link link = new Link(url);
            crawler.setRoot(link);
            crawler.setMaxDepth(7);

            //DownloadParameters dp = new DownloadParameters();
            //dp.changeObeyRobotExclusion(false);
            //dp.changeUserAgent("MyCrawler Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8.1.4) " + "WebSPHINX 0.5 contact me_at_mycompany_dot_com");
            //crawler.setDownloadParameters(dp);
            crawler.setDomain(FeedCrawler.ALL_LINKS);
            //crawler.setRoot(new URL());

            //Inicia a thread de crawler
            t = new Thread(crawler);
            t.start();
        } catch (MalformedURLException malformedURLException) {
            System.out.println("------------------------------------------------");
            System.out.println("URL MALFORMED!");
            System.out.println("------------------------------------------------");
            System.out.println(malformedURLException);
            System.out.println("------------------------------------------------");
        } finally {
            url = null;
//            crawler = null;
//            t = null;
            //Redirect response
            response.sendRedirect(PINOCONTROLLERDO);
            out.close();

        }

    }

    public static void searchFeedsF(PrintWriter out, HttpServletRequest request, HttpServletResponse response) throws Exception {
        ArrayList<FeedUrl> results = new ArrayList<FeedUrl>();
        StringBuilder sb = new StringBuilder();
        String words = request.getParameter(WORDS);
        Scanner sc = new Scanner(words);
        String token = null;

        while (sc.hasNext()) {

            token = sc.next().toUpperCase();
            List<FeedUrl> lLocal = findByTitleLike(token);

            if (lLocal.size() > 0) {
                results.addAll(lLocal);
            }
            lLocal = null;
            token = null;
        }

        //Monta os links
        for (FeedUrl f : results) {
            sb.append("<tr>");
            sb.append("<td>");
            sb.append(f.getTitulo());
            sb.append("</td><td><div align=center><a href=javascript:void())><img border=0 src=images/comment_rss_add_16.png width=16 height=16 /></a></div></td><td><div align=center><a href=javascript:loadFeed('" + f.getUrl() + "')><img border=0 src=images/check_all_16.png alt=Visit width=16 height=16 border=0 /></a></div></td></tr>");
        }

        HttpSession s = request.getSession(true);

        s.setAttribute(RESULTS, sb.toString());
        s.setAttribute(TOTALRESULTS, results.size());

        //dispose
        words = null;
        s = null;
        sb = null;

        //Clear collection
        results.clear();
        results = null;

        //Close and dispose;
        sc.close();
        sc = null;

        response.sendRedirect(SEARCHJSP);
        out.close();
    }

    private static void getTwitterTags() {
        java.util.Date d = new java.util.Date();
        StringBuilder sb = new StringBuilder(TWITTERWTAGS);
        sb.append((d.getYear() + 1900));
        sb.append("-");
        sb.append(d.getMonth() + 1);
        sb.append("-");
        sb.append(d.getDate());

        URL twitterTags = null;
        try {
            twitterTags = new URL(sb.toString());
        } catch (MalformedURLException ex) {
            ex.printStackTrace();
        }

        //Read from remote Stream
        BufferedReader in = null;
        JSONObject js = null;
        try {
            in = new BufferedReader(new InputStreamReader(twitterTags.openStream()));

            js = new JSONObject(in.readLine());

//                    System.out.println(js);

            sb = new StringBuilder();
            sb.append((d.getYear() + 1900));
            sb.append("-");
            sb.append(d.getMonth() + 1);
            sb.append("-");
            sb.append(d.getDate());

            JSONArray ja = js.getJSONObject(TRENDS).getJSONArray(sb.toString());

            sb = new StringBuilder();

            for (int i = 0; i < ja.length(); i++) {
                js = ja.getJSONObject(i);

                String[] str = js.getString(QUERY).split(" ");

                for (String s : str) {
                    Tag t = new Tag();
                    try {
                        t.setTxt(s.replace("#", "").toUpperCase());
                        persist(t);
//                        sb.append(t.getTxt());
//                        sb.append("-");
                    } catch (Exception ex) {
                        Logger.getLogger(FeedFacade.class.getName()).log(Level.SEVERE, null, ex);
                    }
                    t = null;
                    s = null;
                }
                js = null;
                str = null;
            }

        } catch (JSONException ex) {
            Logger.getLogger(FeedFacade.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            Logger.getLogger(FeedFacade.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            try {
                in.reset();
            } catch (IOException ex) {
                Logger.getLogger(FeedFacade.class.getName()).log(Level.SEVERE, null, ex);
            }
            try {
                in.close();
            } catch (IOException ex) {
                Logger.getLogger(FeedFacade.class.getName()).log(Level.SEVERE, null, ex);
            }

            twitterTags = null;
            js = null;
            d = null;
            in = null;
            sb = null;
        }

    }

    private static String getTags() {
        StringBuilder sb = new StringBuilder();

        List<Tag> tags = findTags(100);

        for (Tag t : tags) {
            sb.append("<a href=javascript:alert('");
            sb.append(t.getTxt());
            sb.append("')>");
            sb.append(t.getTxt());
            sb.append("</a>");
        }

        tags.clear();
        tags = null;

        return sb.toString();
    }

    private static synchronized void createSpan(final String email) {
        Runnable r = new Runnable() {

            public void run() {
                Spam spam = new Spam();
                spam.setEmail(email);
                try {
                    persistSpam(spam);
                } catch (Exception ex) {
                    Logger.getLogger(FeedFacade.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        };

        Thread t = new Thread(r);
        t.start();
    }
}
